package com.huajx.jrb.service;

import com.alibaba.fastjson.JSON;
import com.huajx.core.common.Cache;
import com.huajx.core.common.Column;
import com.huajx.core.common.Columns;
import com.huajx.core.common.Paginate;
import com.huajx.jrb.model.Model;
import com.huajx.util.CharsetUtil;
import com.huajx.util.ObjectUtil;
import com.huajx.util.ReflectUtil;
import com.huajx.util.StrUtil;
import com.huajx.util.collection.CollUtil;
import com.huajx.util.collection.CollectionUtil;
import com.huajx.util.io.FileUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class BaseService<T extends Model> {
    private File file;
    private List<T> models;

    protected BaseService(Class<T> modelClass) {
        initFilePath(modelClass);
    }

    private void initFilePath(Class<T> modelClass) {
        String name = modelClass.getName();
        String fileKey = "file-" + name;
        String modelsKey = "models-" + name;

        file = Cache.get(fileKey);

        String file_path = "data/" + modelClass.getSimpleName() + ".json";

        if (file == null) {
            file = FileUtil.file(file_path);
            Cache.set(fileKey, file);
        }

        if (!FileUtil.exist(file)) {
            FileUtil.touch(file);
            models = new ArrayList<>();
            Cache.set(modelsKey, models);
            return;
        }

        models = Cache.get(modelsKey);

        if (models == null) {
            String data = FileUtil.readUtf8String(file);
//
            if (StrUtil.isNotBlank(data)) {
                models = JSON.parseArray(data, modelClass);
            }
            Cache.set(modelsKey, models);
        }
    }

    public Paginate<T> paginate(Columns conditions, int pi, int ps) {
        Paginate<T> page = new Paginate<>();
        int total = models.size();
        int start = (pi - 1) * ps;
        start = start > 0 ? start : 0;

        int end = pi * ps;

        List<T> list = findBy(conditions);

        int filter = list.size();

        end = end > filter ? filter : end;

        page.setList(list.subList(start, end));
        page.setPi(pi);
        page.setPs(ps);
        page.setTotal(total);
        return page;
    }

    public List<T> findBy(Map<String, Object> conditions) {
        if (conditions == null || conditions.isEmpty()) {
            return models;
        }

        return CollUtil.filter(models, (T model) -> {
            boolean flag = true;
            for (Map.Entry<String, Object> entry : conditions.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();

                if (value == null) {
                    continue;
                }
                Object obj = ReflectUtil.getFieldValue(model, key);

                flag = flag && ObjectUtil.equal(value, obj);
            }
            return flag;
        });
    }

    public List<T> findBy(Columns conditions) {
        if (conditions == null || conditions.isEmpty()) {
            return models;
        }

        return CollUtil.filter(models, (T model) -> {
            boolean flag = true;
            for (Column column : conditions.getList()) {
                flag = flag && column.valid(model);
            }
            return flag;
        });
    }

    public T findById(Long id) {
        return CollUtil.findOne(models, (model) -> model.getId().equals(id));
    }

    public void save(T model) {

        if (models.isEmpty()) {
            model.setId(1L);
        } else {
            T end = models.get(models.size() - 1);
            Long id = end.getId();
            model.setId(id + 1L);
        }

        models.add(model);

        write();
    }

    public void update(T model) {
        CollectionUtil.forEach(models.iterator(), (T t, int i) -> {
            if (t.getId().equals(model.getId())) {
                models.set(i, model);
            }
        });

        write();
    }

    public void delete(Long id) {
        if (id == null) {
            return;
        }

        models.removeIf((temp) -> id.equals(temp.getId()));

        write();
    }

    protected void write() {
        if (!FileUtil.exist(file)) {
            FileUtil.touch(file);
        }

        FileUtil.writeString(JSON.toJSONString(models), file, CharsetUtil.CHARSET_UTF_8);
    }
}
